/*
  Copyright © 2010  Vinícius dos Santos Oliveira
  Copyright © 2010  José Cavalcante Reis Neto

      This file is part of Touché.

      Touché is free software: you can redistribute it and/or modify
      it under the terms of the GNU Lesser General Public License as published
      by the Free Software Foundation, either version 3 of the License, or
      (at your option) any later version.

      This program is distributed in the hope that it will be useful,
      but WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      GNU Lesser General Public License for more details.

      You should have received a copy of the GNU Lesser General Public License
      along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */

#include "audioelement.h"
#include "widgets/pushbuttonitem.h"
#include <QGraphicsScene>
using namespace Touche;
#include <QGraphicsSvgItem>
#include <QPainter>
#include <iostream>
#include <QFile>
using std::cout;
using std::endl;
#include <QDateTime>
#include <QDebug>

// class TextItem

LineEditItem::LineEditItem(QString &string, QGraphicsItem *parent, QGraphicsScene *scene) :
        QGraphicsTextItem(parent, scene),
        string(string)
{
    QGraphicsTextItem::setFont(QFont("purisa", 16, 48));
    QGraphicsTextItem::setPlainText(string);
    QGraphicsTextItem::setTextInteractionFlags(Qt::TextEditorInteraction);
}

void LineEditItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    painter->setPen(QPen(QBrush(QColor(0x8F, 0x85, 0, 0xC8)), Qt::SolidPattern));
    painter->setBrush(QBrush(QColor(0xF3, 0xE9, 0x15, 0xFF), Qt::SolidPattern));
    painter->drawRoundedRect(QGraphicsTextItem::boundingRect(), 5., 5., Qt::RelativeSize);
    QGraphicsTextItem::paint(painter, option, widget);
}

void LineEditItem::focusOutEvent(QFocusEvent *event)
{
    QGraphicsTextItem::focusOutEvent(event);
    string = QGraphicsTextItem::toPlainText();
}

// class AudioElement

inline void print(GstElement *element)
{
    GString *string = g_string_new(NULL);
    gst_print_element_args(string, 4, element);
    g_print("%s\n", string->str);
}

static const QString type("audio");
static GstFormat format = GST_FORMAT_TIME;
static gint64 length = 0;

enum Pipeline
{
    RECORD,
    PLAY
};

quint32 AudioElement::counter = 0;
int AudioElement::count = 0;
bool AudioElement::recording = false;
bool AudioElement::playing = false;
QTimer AudioElement::onPlayFinish;
GstElement *AudioElement::pipelines[2] = {NULL, NULL};
GstElement *AudioElement::fileSink = NULL;
GstElement *AudioElement::fileSrc = NULL;

void on_pad_added(GstElement *element, GstPad *source_pad, gpointer data)
{
    AudioElement *object = static_cast<AudioElement *>(g_object_get_data(G_OBJECT(element), "this"));

    GstElement *decoder = static_cast<GstElement *>(data);
    GstPad *sink_pad = gst_element_get_static_pad(decoder, "player_sink");
    gst_pad_link(source_pad, sink_pad);
    gst_object_unref(sink_pad);

    gst_element_query_duration(GST_ELEMENT_PARENT(element), &format, &length);
    object->onPlayFinish.start(length / 1000000);
}

AudioElement::AudioElement() :
        locked(false),
        m_item(new QGraphicsSvgItem(":/gfx/svg/media-tape.svg")),
        m_descriptionItem(new QGraphicsTextItem(QString("NULL AUDIO"), m_item))
{
    if(!count){
        // pipeline to record

        pipelines[RECORD] = gst_pipeline_new("recorder");
        GstElement *source = gst_element_factory_make("pulsesrc", NULL);
        GstElement *encoder = gst_element_factory_make("speexenc", NULL);
        g_object_set(G_OBJECT(encoder),
                     "vad", TRUE,
                     "quality", 10.,
                     NULL);
        GstElement *muxer = gst_element_factory_make("oggmux", NULL);
        fileSink = gst_element_factory_make("filesink", "file_sink");

        gst_bin_add_many(GST_BIN(pipelines[RECORD]), source, encoder, muxer, fileSink, NULL);

        gst_element_link_filtered(source, encoder, gst_caps_new_simple("audio/x-raw-int",
                                                                       "rate",     G_TYPE_INT, 44100,
                                                                       "channels", G_TYPE_INT, 1,
                                                                       "depth",    G_TYPE_INT, 16,
                                                                       "width",    G_TYPE_INT, 16,
                                                                       NULL));
        gst_element_link_many(encoder, muxer, fileSink, NULL);

        // pipeline to play

        pipelines[PLAY] = gst_pipeline_new("player");
        fileSrc = gst_element_factory_make("filesrc", "file_source");

        GstElement *demuxer = gst_element_factory_make("oggdemux", NULL);
        GstElement *decoder = gst_element_factory_make("speexdec", NULL);
        GstElement *sink = gst_element_factory_make("pulsesink", NULL);

        gst_bin_add_many(GST_BIN(pipelines[PLAY]), fileSrc, decoder, demuxer, sink, NULL);

        gst_element_link(fileSrc, demuxer);
        gst_element_link_pads(decoder, "src", sink, "player_sink");

        g_object_set_data(G_OBJECT(demuxer), "this", reinterpret_cast<void *>(this));
        g_signal_connect(demuxer, "pad-added", G_CALLBACK(on_pad_added), decoder);
    }
    ++count;

    m_options.reserve(2);
    m_options.append("record");

    fileName = "audio_" + id + ".spx";
    description = "Audio " + QString::number(counter++);
}

AudioElement::~AudioElement()
{
    if(!count){
        // pipeline to record

        gst_element_set_state(pipelines[RECORD], GST_STATE_NULL);
        gst_object_unref(pipelines[RECORD]);
        pipelines[RECORD] = NULL;

        fileSink = NULL;

        // pipeline to play

        gst_element_set_state(pipelines[PLAY], GST_STATE_NULL);
        gst_object_unref(pipelines[PLAY]);
        pipelines[PLAY] = NULL;

        fileSrc = NULL;
    }
    --count;

    if(!m_null){
        QFile::remove(fileName);
    }
}

const QString &AudioElement::type() const
{
    return ::type;
}

QRectF AudioElement::item(QGraphicsItem *parentItem) const
{
    m_item->setParentItem(parentItem);
    return m_item->boundingRect();
}

QVector<QString> AudioElement::menuOptions() const
{
    return m_options;
}

void AudioElement::onMenuActived(const QString &option)
{
    if(option == "record"){
        if(playing){
            gst_element_set_state(pipelines[RECORD], GST_STATE_PAUSED);
        }

        g_object_set(G_OBJECT(fileSink),
                     "location", fileName.toStdString().c_str(),
                     NULL);

        gst_element_set_state(pipelines[RECORD], GST_STATE_PLAYING);

        m_options[0] = "stop record";
        emit menuUpdated(m_options);
    }else if(option == "play"){
        if(playing){
            gst_element_set_state(pipelines[PLAY], GST_STATE_PAUSED);
        }

        g_object_set(G_OBJECT(fileSrc),
                     "location", fileName.toStdString().c_str(),
                     NULL);

        gst_element_set_state(pipelines[PLAY], GST_STATE_PLAYING);
    }else if(option == "stop record"){
        gst_element_set_state(pipelines[RECORD], GST_STATE_NULL);
        m_options[0] = "play";
        emit menuUpdated(m_options);
    }else if(option == "legend"){
        emit sceneRequest();
    }
}

void AudioElement::onSceneReceived(QGraphicsScene *scene)
{
//    PushButtonItem *recordButton = new PushButtonItem(":/gfx/svg/button-record.svg");
//    recordButton->setCheckable(true);
//    recordButton->setY(64.);
//    recordButton->setScale(8.);
//    scene->addItem(recordButton);
//
//    record_pipeline =
//    connect(recordButton, SIGNAL(toggled(bool)), this, SLOT(recorder(bool)));

    // TODO
}

void AudioElement::onElementLocked(bool locked)
{
    // TODO: verify options enabled
    this->locked = locked;
}

void AudioElement::stopEditionMode()
{
    m_descriptionItem->setPlainText(description);
    emit contentsChanged();
    emit stageRequest();
}
